www.gusucode.com > VC++ 图片浏览器的设计与实现+设计文档源码程序 > VC++ 图片浏览器的设计与实现+设计文档源码程序/code/PictView/ClassImage.cpp

    //Download by http://www.NewXing.com
#include "stdafx.h" 
#include "ClassImage.h"
#include <vfw.h>	//为了使用DrawDibDraw()函数
#include <assert.h>

LanFormat __BitCount2Fmt(int nBitCount)
{
	switch(nBitCount)
	{
	case 1:
		return LanF_Index1;
	case 4:
		return LanF_Index4;
	case 8:
		return LanF_Index8;
	case 16:
		return LanF_R5G5B5;
	case 24:
		return LanF_R8G8B8;
	case 32:
		return LanF_A8R8G8B8;
	}
	return LanF_Unkown;
}
BOOL LanImage::Create(int nWidth,int nHeight,int nBitCount,int ndegree,LanFormat eFmt)
{
	Release();
	if (ndegree==1 || ndegree==4)
	{
		m_eFmt = eFmt;
		m_nWidth = nWidth;
		m_nHeight = nHeight;
	}
	else if(ndegree==2 || ndegree==3)
	{
		m_eFmt = eFmt;
		m_nWidth = nHeight;
		m_nHeight = nWidth;
	}
	m_nBitCount = nBitCount;
	m_nPitch = (nWidth * nBitCount + 31) / 32 * 4;
	m_nImage = m_nPitch * nHeight;

	if(nBitCount <= 8)
	{
		m_nPalette = 1 << nBitCount;
		m_pPal = new RGBQUAD[m_nPalette];
	}
	else
	{
		m_nPalette = 0;		//重点在这里
	}

#ifdef UC_USE_DC
	BITMAPINFOHEADER bih;
	memset(&bih,0,sizeof(bih));
	bih.biSize = sizeof(bih);
	bih.biPlanes = 1;
	bih.biWidth = m_nWidth;
	if(UC_SWAP_HEIGHT(1))
		bih.biHeight = m_nHeight;
	else
		bih.biHeight = -m_nHeight;
	bih.biBitCount = m_nBitCount;
	bih.biSizeImage = m_nImage;
	bih.biClrUsed = m_nPalette;
	HDC hdc = ::GetDC(NULL);
	m_hBitmap = CreateDIBSection(hdc,(BITMAPINFO *)&bih,DIB_RGB_COLORS,(void **)&m_pImage,NULL,0);
	::ReleaseDC(NULL,hdc);
#else
	m_pImage = new BYTE[m_nImage];
#endif

	return TRUE;

}

BOOL LanImage::Create_No(int nWidth,int nHeight,int nBitCount,LanFormat eFmt)
{
	VERIFY(nWidth > 0 && nHeight > 0);			//最初为assert();现改为VERIFY()
	VERIFY(nBitCount > 0 && nBitCount <= 32);
	if(eFmt == LanF_Unkown)
		eFmt = __BitCount2Fmt(nBitCount);
	if(eFmt == LanF_Unkown)
		return FALSE;

	Release();

	m_eFmt = eFmt;
	m_nWidth = nWidth;
	m_nHeight = nHeight;
	m_nBitCount = nBitCount;
	m_nPitch = (nWidth * nBitCount + 31) / 32 * 4;
	m_nImage = m_nPitch * nHeight;

	if(nBitCount <= 8)
	{
		m_nPalette = 1 << nBitCount;
		m_pPal = new RGBQUAD[m_nPalette];
	}
	else
	{
		m_nPalette = 0;		//重点在这里
	}

#ifdef UC_USE_DC
	BITMAPINFOHEADER bih;
	memset(&bih,0,sizeof(bih));
	bih.biSize = sizeof(bih);
	bih.biPlanes = 1;
	bih.biWidth = m_nWidth;
	if(UC_SWAP_HEIGHT(1))
		bih.biHeight = m_nHeight;
	else
		bih.biHeight = -m_nHeight;
	bih.biBitCount = m_nBitCount;
	bih.biSizeImage = m_nImage;
	bih.biClrUsed = m_nPalette;
	HDC hdc = ::GetDC(NULL);
	m_hBitmap = CreateDIBSection(hdc,(BITMAPINFO *)&bih,DIB_RGB_COLORS,(void **)&m_pImage,NULL,0);
	::ReleaseDC(NULL,hdc);
#else
	m_pImage = new BYTE[m_nImage];
#endif

	return TRUE;

}

BOOL LanImage::CopyFrom(const LanImage & Img)
{
	if(&Img == this || Img.IsLoad() == FALSE)
		return FALSE;

//	if(Create_No(Img,Img.GetWidth(),Img.GetHeight(),Img.m_eFmt) == FALSE)
//		return FALSE;
//	if(Create_No(Img.GetWidth(),Img.GetHeight(),Img.GetBitCount(),Img.m_eFmt) == FALSE)
//		return FALSE;

	memcpy(m_pImage,Img.GetImage(),GetSize());
	memcpy(m_pPal,Img.GetPalette(),GetPalCount() * sizeof(RGBQUAD));

	return TRUE;
}
//-----------------------------------------------------------------------------
void LanImage::Release()
{
#ifdef UC_USE_DC
	if(m_hBitmap)		//删除的是原始图像数据
	{
		DeleteObject(m_hBitmap);
		//m_pOriginImage指向的是m_hBitmap的图像数据空间,空间被释放,置为NULL
		m_pOriginImage = NULL;
	}

	if(!m_bBufferIsOriginal)
	{
		delete [] m_pImage;
		m_pImage = NULL;
	}
#else
	if(m_pImage)		//若没用定义UC_USE_DC,则此处删的是当前显示的数据
	{
		delete [] m_pImage;
		m_pImage = NULL;
	}

	if(!m_bBufferIsOriginal)
	{
		delete [] m_pOriginImage;
		m_pOriginImage = NULL;
	}
#endif
	if(m_pPal)
	{
		delete [] m_pPal;
		m_pPal = NULL;
	}

//	memset(this,0,sizeof(LanImage));
}
//-----------------------------------------------------------------------------
#ifdef UC_USE_DC
HDC LanImage::GetDC()
{
	HDC hdc = CreateCompatibleDC(NULL);
	SelectObject(hdc,m_hBitmap);
	if(m_nPalette > 0)
		SetDIBColorTable(hdc,0,m_nPalette,m_pPal);
	return hdc;
}

void LanImage::ReleaseDC(HDC hdc)
{
	DeleteDC(hdc);
}

#endif

BOOL LanImage::LoadImage(LPCTSTR pszFileName,int ndegree,BOOL isconvert)
{
	//判断文件的后缀名,以决定图像是何格式.这种方法并不太好,理想的方法应该是读取文件
	//数据并从中取得图像格式的信息。
	LPCTSTR pszExt = _tcsrchr(pszFileName,_T('.'));		//取后缀名
	BOOL bRet = FALSE;

	//如为JPEG格式,则采用Lib Sources中的读法
	if( (_tcsicmp(pszExt,".jpg") == 0) || (_tcsicmp(pszExt,".jpeg") == 0) )
	{
		m_bReadWithLibSupport = TRUE;
		m_pJpeg = new CJpeg();
		//int size = sizeof(m_pJpeg);
		//CString str;
		//str.Format("%d",size);
		//AfxMessageBox(str);////////////
		bRet = m_pJpeg->Load(pszFileName);

		if(!bRet)
		{
			AfxMessageBox("载入JPEG文件时发生错误!");
			return FALSE;
		}

		CDib *pDib = m_pJpeg->GetDib();	//获取CDib指针
		m_pImage = pDib->GetBitsPtr();	//获取DIB数据区指针
		m_nWidth = pDib->GetWidth();
		m_nHeight = pDib->GetHeight();
		m_nBitCount = pDib->GetBitCount();
		m_nImage = m_nHeight*(pDib->GetWidthBytes());
		m_nPitch = pDib->GetWidthBytes();
		m_nPalette = 0;
		//为了得到文件的长度
		CFile file;
		if(file.Open(pszFileName,CFile::modeRead) == FALSE)
		{
			AfxMessageBox("获取文件大小错误:无法打开文件!");
			return FALSE;
		}
		nFileSize = file.GetLength();
		file.Close();
	}
	//如为GIF格式,也采用Lib Sources中的读法
	else if( _tcsicmp(pszExt,".gif") == 0 )
	{
		m_bReadWithLibSupport = TRUE;
		m_pGif = new CGif();
		bRet = m_pGif->Load(pszFileName);

		if(!bRet)
		{
			AfxMessageBox("载入GIF文件时发生错误!");
			return FALSE;
		}

		CDib *pDib = m_pGif->GetDib();	//获取CDib指针
		m_pImage = pDib->GetBitsPtr();	//获取DIB数据区指针
		m_nWidth = pDib->GetWidth();
		m_nHeight = pDib->GetHeight();
		m_nBitCount = pDib->GetBitCount();
		m_nImage = m_nHeight*(pDib->GetWidthBytes());
		m_nPitch = pDib->GetWidthBytes();
		m_nPalette = 0;
		//为了得到文件的长度
		CFile file;
		if(file.Open(pszFileName,CFile::modeRead) == FALSE)
		{
			AfxMessageBox("获取文件大小错误:无法打开文件!");
			return FALSE;
		}
		nFileSize = file.GetLength();
		file.Close();
	}
	else
	{
		m_bReadWithLibSupport = FALSE;
		CFile file;
		if(file.Open(pszFileName,CFile::modeRead) == FALSE)
		{
			AfxMessageBox("无法打开文件!请确认文件是否存在或路径是否正确!");
			return FALSE;
		}

		// 为了得到文件的长度。
		nFileSize = file.GetLength();
	
		BYTE * pFileBuffer = new BYTE[nFileSize]; //

		file.Read(pFileBuffer,nFileSize);

		file.Close();

//##**##
		if(_tcsicmp(pszExt,".bmp") == 0)
			bRet = ReadBmp(pFileBuffer,nFileSize,ndegree,isconvert);
		else if(_tcsicmp(pszExt,".tga") == 0)
			bRet = ReadTga(pFileBuffer,nFileSize,ndegree);
		else if(_tcsicmp(pszExt,".pcx") == 0)
			bRet = ReadPcx(pFileBuffer,nFileSize,ndegree);

		delete [] pFileBuffer;
		pFileBuffer = NULL;
	}

	return bRet;
}

struct LanDrawDib
{
	HDRAWDIB hDraw;
	LanDrawDib()
	{
		hDraw = DrawDibOpen();
	}

	~LanDrawDib(){
		DrawDibClose(hDraw);
	}

	operator HDRAWDIB ()
	{
		return hDraw;
	}

	static LanDrawDib & GetDrawDib()
	{
		static LanDrawDib	__DrawDib;
		return __DrawDib;
	}
};


struct LanDrawHeader : public BITMAPINFOHEADER
{
	RGBQUAD	pal[256];
	LanDrawHeader(){
		memset(this,0,sizeof(LanDrawHeader));
		biSize = sizeof(BITMAPINFOHEADER);
		biPlanes = 1;
	}
};

static LanDrawHeader  g_LanDH;

BOOL LanImage::Draw(HDC hdc,int nDx,int nDy,int nDw,int nDh,
				int nSx,int nSy,int nSw,int nSh,UINT uFlags) const
{
	if(IsLoad() == FALSE)
		return FALSE;

	g_LanDH.biWidth = m_nWidth;
	g_LanDH.biHeight = m_nHeight;
	g_LanDH.biBitCount = m_nBitCount;
	if(m_nBitCount <= 8)
	{
//		memcpy(g_LanDH.pal,m_pPal,(1 << m_nBitCount) * sizeof(RGBQUAD));
		g_LanDH.biClrUsed = m_nPalette;
		memcpy(g_LanDH.pal,m_pPal,m_nPalette * sizeof(RGBQUAD));
	}

	DrawDibDraw(LanDrawDib::GetDrawDib(),hdc,
		nDx,nDy,nDw,nDh,
		&g_LanDH,m_pImage,
		nSx,nSy,nSw,nSh,
		uFlags);

	return TRUE;
}

//**** 此函数为了在打开图像时没有创建CDib的情况下创建CDib对象 ****
BOOL LanImage::CreateDib(CDib **pDib)
{
	BITMAPINFOHEADER	bmiHeader;
	HDIB				hDIB;
	bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	bmiHeader.biWidth = m_nWidth;
	bmiHeader.biHeight = m_nHeight;
	bmiHeader.biPlanes = 1;
	bmiHeader.biBitCount = m_nBitCount;
	bmiHeader.biCompression = BI_RGB;
	bmiHeader.biSizeImage = m_nImage;
	bmiHeader.biXPelsPerMeter = 0;
	bmiHeader.biYPelsPerMeter = 0;
	//如果打开的图片BitCount>8则无调色板
	if(m_nBitCount>8)
		bmiHeader.biClrUsed = 0;
	else
		bmiHeader.biClrUsed = m_nPalette;
	bmiHeader.biClrImportant = 0;
	
	// Allocate enough memory for the new CF_DIB, and copy bits 
	DWORD dwHeaderSize = sizeof(BITMAPINFOHEADER);
	DWORD dwPaletteSize = sizeof(RGBQUAD)*m_nPalette;
	DWORD dwBitsSize = WIDTHBYTES(m_nWidth*m_nBitCount) * m_nHeight;
	if(m_nBitCount>8)
		hDIB = GlobalAlloc(GHND, dwHeaderSize + dwBitsSize);
	else
		hDIB = GlobalAlloc(GHND, dwHeaderSize + dwPaletteSize + dwBitsSize);

	if (hDIB == NULL)
		return FALSE;
		
	LPBYTE lpDIB = (LPBYTE)GlobalLock(hDIB); 
	memcpy(lpDIB, (LPBYTE)&bmiHeader, dwHeaderSize);
	if(m_nBitCount<=8)		//写调色板
		memcpy(lpDIB+dwHeaderSize,m_pPal,dwPaletteSize);
	memcpy(FindDIBBits((LPBYTE)lpDIB), m_pImage, dwBitsSize);

	*pDib = new CDib();
	(*pDib)->Attach(hDIB);
	GlobalUnlock(hDIB);
	return TRUE;
}

//****** 旋转图像-顺时针90度 ********
//
//		注意图像的4字节对齐!!!
//
//-----------------------------------
void LanImage::Rotate90Clockwise()
{
	BYTE* pNewImage = NULL;
	
	int iSrcWidth = m_nWidth;
	int iSrcHeight = m_nHeight;
	int iSrcRowBytes = m_nPitch;

	//计算翻转后一行占用的字节数及数据区的大小
	int iNewPitch = (iSrcHeight * m_nBitCount + 31) / 32 * 4;	//4字节对齐
	int iNewImgDataSize = iNewPitch * iSrcWidth;

	//为翻转后的数据分配空间
	pNewImage = new BYTE[iNewImgDataSize];
	switch(m_nBitCount)
	{
	case 8:	//8位图像的翻转
		{
			int OutPointer = 0;
			for(int y = 0;y < iSrcHeight;y++)
			{
				BYTE *pIn = GetLine(y);
				for(int x = 0;x < iSrcWidth;x++)
				{
					int OutColumn = y;				//这两行看起来是做逆时针旋转,但由于DIB
					int OutRow = iSrcWidth - x - 1;	//是由下到上存储图像的,故实际上是顺时针
					//int OutColumn = iSrcHeight - y - 1;//而这两行注释掉的则正相反,是逆时针的
					//int OutRow = x;
					OutPointer = OutRow * iNewPitch + OutColumn;
					CopyMemory(&pNewImage[OutPointer],&pIn[x],1);
				}
			}
		}
		break;
	case 1:		//1位和4位比较麻烦,要对位进行操作
		{
			memset(pNewImage,0,iNewImgDataSize);	//全置为0,便于后面的按位或操作
			int OutPointer = 0;
			for(int y=0;y<iSrcHeight;y++)
			{
				BYTE* pIn = GetLine(y);
				for(int x=0;x<iSrcRowBytes;x++)
				{
					int BitPointer = 0;		//确定是在该字节中的第几位
					int OutColumn = y/8;	//8行翻转后才构成一字节
					BYTE byTempIn = pIn[x];	//取一个字节,即8个象素
					BYTE byTempOut;

					for(BitPointer=0;BitPointer<8;BitPointer++)
					{
						int OutRow = iSrcWidth - (x*8+BitPointer) - 1;
						//注意:最高位代表最左边的象素!
						switch(BitPointer)
						{
						case 0:
							byTempOut = (byTempIn & 0x80);	//1000 0000
							byTempOut = (byTempOut >> (y%8));//得出此位在目的字节中应在哪一位
							break;
						case 1:
							byTempOut = (byTempIn & 0x40);	//0100 0000
							if(y%8-1 < 0)
								byTempOut = (byTempOut << (1-y%8));
							else
								byTempOut = (byTempOut >> (y%8-1));
							break;
						case 2:
							byTempOut = (byTempIn & 0x20);	//0010 0000
							if(y%8-2 < 0)
								byTempOut = (byTempOut << (2-y%8));
							else
								byTempOut = (byTempOut >> (y%8-2));
							break;
						case 3:
							byTempOut = (byTempIn & 0x10);	//0001 0000
							if(y%8-3 < 0)
								byTempOut = (byTempOut << (3-y%8));
							else
								byTempOut = (byTempOut >> (y%8-3));
							break;
						case 4:
							byTempOut = (byTempIn & 0x08);	//0000 1000
							if(y%8-4 < 0)
								byTempOut = (byTempOut << (4-y%8));
							else
								byTempOut = (byTempOut >> (y%8-4));
							break;
						case 5:
							byTempOut = (byTempIn & 0x04);	//0000 0100
							if(y%8-5 < 0)
								byTempOut = (byTempOut << (5-y%8));
							else
								byTempOut = (byTempOut >> (y%8-5));
							break;
						case 6:
							byTempOut = (byTempIn & 0x02);	//0000 0010
							if(y%8-6 < 0)
								byTempOut = (byTempOut << (6-y%8));
							else
								byTempOut = (byTempOut >> (y%8-6));
							break;
						case 7:
							byTempOut = (byTempIn & 0x01);	//0000 0001
							byTempOut = (byTempOut << (7-y%8));
							break;
						}

						OutPointer = OutRow * iNewPitch +OutColumn;
						BYTE byDestBuffer = pNewImage[OutPointer];
						byDestBuffer = (byDestBuffer | byTempOut);
						pNewImage[OutPointer] = byDestBuffer;
					}//for(BitPointer)
				}//for(x)
			}//for(y)
		}
		break;
	case 4:
		{
			memset(pNewImage,0,iNewImgDataSize);	//全置为0,便于后面的按位或操作
			int OutPointer = 0;
			for(int y=0;y<iSrcHeight;y++)
			{
				BYTE* pIn = GetLine(y);
				for(int x=0;x<iSrcRowBytes;x++)
				{
					int PixPointer = 0;		//确定是在该字节中的第几个象素
					int OutColumn = y/2;	//2行翻转后构成一字节
					BYTE byTempIn = pIn[x];	//取一个字节,即2个象素
					BYTE byTempOut;

					for(PixPointer=0;PixPointer<2;PixPointer++)
					{
						int OutRow = iSrcWidth - (x*2+PixPointer) - 1;
						//注意:最高位代表最左边的象素!
						switch(PixPointer)
						{
						case 0:
							byTempOut = (byTempIn & 0xF0);	//1111 0000
							byTempOut = (byTempOut >> (y%2*4));
							break;
						case 1:
							byTempOut = (byTempIn & 0x0F);	//0000 1111
							byTempOut = (byTempIn << (4-y%2*4));
							break;
						}

						OutPointer = OutRow * iNewPitch +OutColumn;
						BYTE byDestBuffer = pNewImage[OutPointer];
						byDestBuffer = (byDestBuffer | byTempOut);
						pNewImage[OutPointer] = byDestBuffer;
					}//for(PixPointer)
				}//for(x)
			}//for(y)
		}
		break;
	case 16:
		{
			int OutPointer = 0;
			for(int y = 0;y < iSrcHeight;y++)
			{
				BYTE *pIn = GetLine(y);
				for(int x = 0;x < iSrcWidth;x++)
				{
					//16位时一个象素占两字节宽
					int OutColumn = y*2;			//这两行看起来是做逆时针旋转,但由于DIB
					int OutRow = iSrcWidth - x - 1;	//是由下到上存储图像的,故实际上是顺时针
					//int OutColumn = iSrcHeight - y - 1;//而这两行注释掉的则正相反,是逆时针的
					//int OutRow = x;
					OutPointer = OutRow * iNewPitch + OutColumn;
					CopyMemory(&pNewImage[OutPointer],&pIn[x*2],2);
				}
			}
		}
		break;
	case 24:
		{
			int OutPointer = 0;
			for(int y = 0;y < iSrcHeight;y++)
			{
				BYTE *pIn = GetLine(y);
				for(int x = 0;x < iSrcWidth;x++)
				{
					//16位时一个象素占三字节宽
					int OutColumn = y*3;			//这两行看起来是做逆时针旋转,但由于DIB
					int OutRow = iSrcWidth - x - 1;	//是由下到上存储图像的,故实际上是顺时针
					//int OutColumn = iSrcHeight - y - 1;//而这两行注释掉的则正相反,是逆时针的
					//int OutRow = x;
					OutPointer = OutRow * iNewPitch + OutColumn;
					CopyMemory(&pNewImage[OutPointer],&pIn[x*3],3);
				}
			}
		}
		break;
	case 32:
		{
			int OutPointer = 0;
			for(int y = 0;y < iSrcHeight;y++)
			{
				BYTE *pIn = GetLine(y);
				for(int x = 0;x < iSrcWidth;x++)
				{
					//16位时一个象素占四字节宽
					int OutColumn = y*4;			//这两行看起来是做逆时针旋转,但由于DIB
					int OutRow = iSrcWidth - x - 1;	//是由下到上存储图像的,故实际上是顺时针
					//int OutColumn = iSrcHeight - y - 1;//而这两行注释掉的则正相反,是逆时针的
					//int OutRow = x;
					OutPointer = OutRow * iNewPitch + OutColumn;
					CopyMemory(&pNewImage[OutPointer],&pIn[x*4],4);
				}
			}
		}
		break;
	}

	//打开图像后未做变换,则不能delete,因这时的m_pImage指向的空间不是在此new出来的
	if(m_bBufferIsOriginal)
	{
		m_pOriginImage = m_pImage;	//保留原来的图像数据
		m_nOriginWidth = m_nWidth;
		m_nOriginHeight = m_nHeight;
		m_nOriginPitch = m_nPitch;
		m_nOriginImage = m_nImage;
	}
	else
		delete [] m_pImage;

	m_pImage = pNewImage;
	pNewImage = NULL;
	//交换宽高[!-注意:不能在此函数开头就改变m_LImage的宽高,因为在从源数据区取数据时用到了
	//GetLine()函数,而此函数与原图片的宽高和m_nPitch有关,如开始就破坏了原图片的宽高值,
	//那么将得到错误的结果。-]
	m_nWidth = iSrcHeight;
	m_nHeight = iSrcWidth;
	m_nPitch = iNewPitch;
	m_nImage = iNewImgDataSize;
	m_bBufferIsOriginal = FALSE;
}